package com.xjgzinfo.usdp.web.rest;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xjgzinfo.lowcode.common.DataSourcePropertiesDTO;
import com.xjgzinfo.lowcode.common.MultiRouteDataSource;
import com.xjgzinfo.lowcode.common.QueryMapDTO;
import com.xjgzinfo.lowcode.service.DataSourceService;
import com.xjgzinfo.lowcode.service.DynamicQueryService;
import com.xjgzinfo.usdp.core.domain.PageWapper;
import com.xjgzinfo.usdp.core.domain.ResponsePage;
import com.xjgzinfo.usdp.core.domain.ResponseResult;
import com.xjgzinfo.usdp.jpa.service.filter.IntegerFilter;
import com.xjgzinfo.usdp.service.BladeVisualDbQueryService;
import com.xjgzinfo.usdp.service.BladeVisualDbService;
import com.xjgzinfo.usdp.service.dto.BladeVisualDbCriteria;
import com.xjgzinfo.usdp.service.dto.BladeVisualDbDTO;
import com.xjgzinfo.usdp.service.ext.DataSourcePropertiesDTOMapper;
import com.xjgzinfo.usdp.service.vo.BladeVisualDbVO;
import com.xjgzinfo.usdp.service.vo.BladeVisualVOEntityMapper;
import com.xjgzinfo.usdp.web.rest.utils.BeanUtilsHepler;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * REST controller for managing {@link com.xjgzinfo.usdp.domain.BladeVisualDb}.
 */
@RestController
@RequestMapping("/blade-visual")
public class DbResource {

    private static final String ENTITY_NAME = "AvueServer4jAppBladeVisualDb";
    public final MultiRouteDataSource multiDataSource;
    private final Logger log = LoggerFactory.getLogger(DbResource.class);
    private final BladeVisualDbService bladeVisualDbService;
    private final BladeVisualDbQueryService bladeVisualDbQueryService;
    private final DataSourceService dataSourceService;
    private final DynamicQueryService dynamicQueryService;
    private final ObjectMapper objectMapper;
    @Value("${spring.application.name:usdp-app-unkown}")
    private String applicationName;
    @Value("${usdp.aes-key:O2BEeIv399qHQNhD6aGW8R8DEj4bqHXm}")
    private String aesKey;

    public DbResource(MultiRouteDataSource multiDataSource, BladeVisualDbService bladeVisualDbService, BladeVisualDbQueryService bladeVisualDbQueryService, DynamicQueryService dynamicQueryService, DataSourceService dataSourceService, ObjectMapper objectMapper) {
        this.bladeVisualDbService = bladeVisualDbService;
        this.bladeVisualDbQueryService = bladeVisualDbQueryService;
        this.dynamicQueryService = dynamicQueryService;
        this.dataSourceService = dataSourceService;
        this.objectMapper = objectMapper;
        this.multiDataSource = multiDataSource;
        this.initDataSource();
    }

    private void initDataSource() {
        BladeVisualDbCriteria criteria = new BladeVisualDbCriteria();
        IntegerFilter isDelete = new IntegerFilter();
        IntegerFilter status = new IntegerFilter();
        status.setEquals(1);
        isDelete.setEquals(0);
        criteria.setIsDeleted(isDelete);
        criteria.setStatus(status);
        List<BladeVisualDbDTO> bladeVisualDbDTOS = bladeVisualDbQueryService.findByCriteria(criteria);
        List<DataSourcePropertiesDTO> listDs = DataSourcePropertiesDTOMapper.INSTANCE.doList2doList(bladeVisualDbDTOS);
        List<Boolean> results = this.dataSourceService.addDataSources(listDs);
        log.info("success add dataSource : {} / {}", results.stream().filter(it -> it.equals(true)).count(), results.size());
    }

    /**
     * {@code POST  /db/save} : 创建实体 bladeVisualDb.
     *
     * @param bladeVisualDbDTO the bladeVisualDbDTO to create.
     * @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the new bladeVisualDbDTO, or with status {@code 400 (Bad Request)} if the bladeVisualDb has already an ID.
     * @throws URISyntaxException if the Location URI syntax is incorrect.
     */
    @PostMapping("/db/save")
    public ResponseResult<BladeVisualDbVO> createBladeVisualDb(@Valid @RequestBody BladeVisualDbDTO bladeVisualDbDTO) throws URISyntaxException {
        log.debug("REST request to save BladeVisualDb : {}", bladeVisualDbDTO);
        if (bladeVisualDbDTO.getId() != null) {
            return new ResponseResult(200, null, "ID已存在", false);
        }
        BladeVisualDbDTO result = bladeVisualDbService.save(bladeVisualDbDTO);
        dataSourceService.addDataSource(DataSourcePropertiesDTOMapper.INSTANCE.do2do(result));
        if (result.getId() != null) {
            return new ResponseResult(200, result, "创建成功", true);
        } else {
            return new ResponseResult(400, result, "创建失败", false);
        }
    }

    /**
     * {@code PUT  /db/update} : 修改实体 bladeVisualDb.
     *
     * @param bladeVisualDbDTO the bladeVisualDbDTO to update.
     * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated bladeVisualDbDTO,
     * or with status {@code 400 (Bad Request)} if the bladeVisualDbDTO is not valid,
     * or with status {@code 500 (Internal Server Error)} if the bladeVisualDbDTO couldn't be updated.
     * @throws URISyntaxException if the Location URI syntax is incorrect.
     */
    @PostMapping("/db/update")
    public ResponseResult<BladeVisualDbVO> updateBladeVisualDb(@Valid @RequestBody BladeVisualDbDTO bladeVisualDbDTO) throws URISyntaxException {
        log.debug("REST request to update BladeVisualDb : {}", bladeVisualDbDTO);
        if (bladeVisualDbDTO.getId() == null) {
            return new ResponseResult(200, null, "ID不能为空", false);
        }
        BladeVisualDbDTO result = null;
        Optional<BladeVisualDbDTO> bladeVisualDbDTOOptional = bladeVisualDbService.findOne(bladeVisualDbDTO.getId());
        if (bladeVisualDbDTOOptional.isPresent()) {
            BladeVisualDbDTO bladeVisualDbDTO_save = bladeVisualDbDTOOptional.get();
            String[] nullPropertyNames = BeanUtilsHepler.getNullPropertyNames(bladeVisualDbDTO);
            BeanUtil.copyProperties(bladeVisualDbDTO, bladeVisualDbDTO_save, nullPropertyNames);
            bladeVisualDbDTO_save.setUpdateTime(Instant.now());
            result = bladeVisualDbService.save(bladeVisualDbDTO_save);
            //更新数据源
            this.dataSourceService.removeDataSource(result.getName());
            dataSourceService.addDataSource(DataSourcePropertiesDTOMapper.INSTANCE.do2do(result));
        }
        return new ResponseResult(200, BladeVisualVOEntityMapper.INSTANCE.do2Vo(result), "修改成功", true);
    }

    /**
     * {@code GET  /db/list} : 分页获取实体列表 bladeVisualDbs.
     *
     * @param pageable the pagination information.
     * @param criteria the criteria which the requested entities should match.
     * @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of bladeVisualDbs in body.
     */
    @GetMapping("/db/list")
    public ResponsePage<BladeVisualDbVO> getAllBladeVisualDbs(BladeVisualDbCriteria criteria, Pageable pageable) {
        log.debug("REST request to get BladeVisualDbs by criteria: {}", criteria);
        Page<BladeVisualDbDTO> page = bladeVisualDbQueryService.findByCriteria(criteria, pageable);
        PageWapper<BladeVisualDbVO> pageWapper = new PageWapper(page.getNumber(), page.getTotalPages(), BladeVisualVOEntityMapper.INSTANCE.doList2VoList(page.getContent()), page.getSize(), page.getTotalElements());
        return new ResponsePage(200, pageWapper, "", true);
    }

    /**
     * {@code GET  /db/count} : count all the bladeVisualDbs.
     *
     * @param criteria the criteria which the requested entities should match.
     * @return the {@link ResponseEntity} with status {@code 200 (OK)} and the count in body.
     */
    @GetMapping("/db/count")
    public ResponseEntity<Long> countBladeVisualDbs(BladeVisualDbCriteria criteria) {
        log.debug("REST request to count BladeVisualDbs by criteria: {}", criteria);
        return ResponseEntity.ok().body(bladeVisualDbQueryService.countByCriteria(criteria));
    }

    /**
     * {@code GET  /db/detail} : ID查询实体 bladeVisualDb.
     *
     * @param id the id of the bladeVisualDbDTO to retrieve.
     * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the bladeVisualDbDTO, or with status {@code 404 (Not Found)}.
     */
    @GetMapping("/db/detail")
    public ResponseResult<BladeVisualDbVO> getBladeVisualDb(@RequestParam(value = "id", required = false) Long id, @RequestParam(value = "id.equals", required = false) Long equalsId) {
        long queryId = id != null ? id : equalsId;
        log.debug("REST request to get BladeVisualDb : {}", queryId);
        Optional<BladeVisualDbDTO> bladeVisualDbDTO = bladeVisualDbService.findOne(queryId);
        if (bladeVisualDbDTO.isPresent()) {
            return new ResponseResult(404, null, "未查询到数据", false);
        }
        return new ResponseResult(200, bladeVisualDbDTO.get(), "", true);
    }

    /**
     * {@code DELETE  /db/remove} : ID删除实体 bladeVisualDb.
     *
     * @param id the id of the bladeVisualDbDTO to delete.
     * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
     */
    @PostMapping("/db/remove")
    public ResponseResult<Void> deleteBladeVisualDb(@RequestParam(value = "id", required = false) Long id, @RequestParam(value = "id.equals", required = false) Long equalsId) {
        long deleteId = id != null ? id : equalsId;
        log.debug("REST request to delete BladeVisualDb : {}", deleteId);
        Optional<BladeVisualDbDTO> bladeVisualDbDTOOpt = bladeVisualDbService.findOne(deleteId);
        if (bladeVisualDbDTOOpt.isPresent()) {
            BladeVisualDbDTO bladeVisualDbDTO = bladeVisualDbDTOOpt.get();
            if (bladeVisualDbDTO.getName() != null) {
                this.dataSourceService.removeDataSource(bladeVisualDbDTO.getName());
                bladeVisualDbService.delete(deleteId);
            }
            return new ResponseResult(200, null, "已删除数据源", true);
        } else {
            return new ResponseResult(404, null, "未查询到数据", false);
        }
    }


    /**
     * {@code POST  /db/db-test} : 测试 Db.
     *
     * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
     */
    @PostMapping("/db/db-test")
    public ResponseResult<Boolean> testDb(@RequestBody String body) {
        SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, aesKey.getBytes(Charset.forName("UTF-8")));
        String str = new String(aes.decrypt(Base64.decode(body)), Charset.forName("UTF-8"));
        return new ResponseResult(200, this.dataSourceService.testDataSource(str), "", true);
    }

    /**
     * {@code POST  /db/dynamic-query} : 测试 Db.
     *
     * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
     */
    @PostMapping("/db/dynamic-query")
    public ResponseResult<List<Map<String, Object>>> dynamicSql(@RequestBody String body) {
        SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, aesKey.getBytes(Charset.forName("UTF-8")));
        String str = new String(aes.decrypt(Base64.decode(body)), Charset.forName("UTF-8"));
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        QueryMapDTO queryMapDTO = new QueryMapDTO();
        try {
            queryMapDTO = objectMapper.readValue(str, queryMapDTO.getClass());
            if (StringUtils.isNotBlank(queryMapDTO.getId())) {
                Optional<BladeVisualDbDTO> bladeVisualDbDTO = bladeVisualDbService.findOne(Long.valueOf(queryMapDTO.getId()));
                if (bladeVisualDbDTO.isPresent() && StringUtils.isNotBlank(queryMapDTO.getSql())) {
                    queryMapDTO.setName(bladeVisualDbDTO.get().getName());
                    if (queryMapDTO.getParams().size() > 0) {
                        list = this.dynamicQueryService.execute(queryMapDTO.getName(), queryMapDTO.getSql(), queryMapDTO.getParams());
                    } else {
                        list = this.dynamicQueryService.execute(queryMapDTO.getName(), queryMapDTO.getSql(), null);
                    }
                }
            }
        } catch (JsonProcessingException e) {
            return new ResponseResult(200, list, e.getMessage(), false);
        }
        return new ResponseResult(200, list, "", true);
    }
}
